package com.webchat.common.util;

import org.springframework.security.crypto.bcrypt.BCrypt;

import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.util.Base64;
import java.util.UUID;

public class AkSkGenerator {

    /**
     * AK前缀标识（企业规范）
     */
    private static final String AK_PREFIX = "ak-";

    /**
     * 生成32位AK（UUIDv4规范）
     *
     * @return
     */
    public static String generateAk() {

        return AK_PREFIX + UUID.randomUUID().toString().replace("-", "").toLowerCase();
    }

    /**
     * 生成32字节SK（加密级随机数）
     *
     * @return
     * @throws NoSuchAlgorithmException
     */
    public static String generateSk() {

        try {
            SecureRandom secureRandom = SecureRandom.getInstanceStrong();
            byte[] skBytes = new byte[32];
            secureRandom.nextBytes(skBytes);
            return Base64.getEncoder().encodeToString(skBytes);
        } catch (Exception e) {
            throw new RuntimeException("SK生成失败！");
        }
    }

    /**
     * HAHS算法，采用BCrypt实现
     *
     * SK加密存储, 使用BCrypt
     * BCrypt哈希值的格式为：$2a$[cost]$[22位盐][31位哈希]
     * 一般不会直接将key存储到数据库，会存储hashKey（随机加盐），更安全
     *
     * 常用对比，BCrypt优势
     * ---------------------------------------------------------------------------------
     * |    方法	           |          问题	                |       BCrypt优势         |
     * ---------------------------------------------------------------------------------
     * |明文存储SK	       | 数据库泄露导致SK直接暴露	        | 哈希不可逆，攻击者无法还原SK |
     * |MD5/SHA-256哈希	   | 无盐易破解，无法防御彩虹表攻击	    | 内置随机盐，相同SK不同哈希   |
     * |自定义加密算法	   |  实现漏洞风险高（如ECB模式）	    | 经过安全社区验证的标准实现   |
     * ---------------------------------------------------------------------------------
     *
     * @param key
     * @return
     */
    public static String hashKey(String key) {

        return BCrypt.hashpw(key, BCrypt.gensalt());
    }

    /**
     * 校验key与hashKey是否相同
     *
     * @param key
     * @param hashKey
     * @return
     */
    public static boolean checkKey(String key, String hashKey) {

        return BCrypt.checkpw(key, hashKey);
    }

    public static void main(String[] args) {
        String ak = generateAk();
        String sk = generateSk();
        System.out.println(ak);
        System.out.println(sk);
        // SK加密存储, 使用BCrypt
        // BCrypt哈希值的格式为：$2a$[cost]$[22位盐][31位哈希]
        String storedHashedSk = hashKey(sk);
        System.out.println(storedHashedSk);
        // 校验sk是否正确
        System.out.println(checkKey(sk, storedHashedSk));
    }
}
